module MEMU(
    input clk,
    input resetn,
    input wire mem_we,
    input wire[31:0]mem_addr_alu,
    input wire[31:0]mem_addr,//即alu_res
    input wire[31:0]mem_w_data,
    input wire[3:0]mem_op,//0为字//1为半字//2为字节
    input wire res_from_mem,
    input wire [31:0]cache_data,
    output wire[31:0] res_data,
    //exc
    output wire exc,
    output wire[5:0] ecode,
    output wire esubcode,
    output wire[31:0] badv,

    output wire busy,


    //data
    output wire         data_rd_req,
    output wire[2 :0]   data_rd_type,
    output wire[31:0]   data_rd_addr,
    input  wire         data_rd_rdy,
    input  wire         data_ret_valid,
    input  wire         data_ret_last,
    input  wire[31:0]   data_ret_data,

    output  wire        data_wr_req,
    output  wire[2 :0]  data_wr_type,
    output  wire[31:0]  data_wr_addr,//写首地址
    output  wire[3 :0]  data_wr_wstrb,
    output  wire[127:0] data_wr_data,
    input   wire        data_wr_rdy
);
//exc
assign exc = (((mem_op[0] == 1 && mem_addr[1:0] != 2'b00) || (mem_op[1] == 1 && mem_addr[0] == 1)) && (res_from_mem || mem_we)) ? 1 : 0;
assign ecode = 6'h09;
assign esubcode = 0;
assign badv = mem_addr;



//---------------------------------Dcache---------------------------------
reg  flag=1;
wire data_cache_addr_ok;
wire data_cache_data_ok;
wire data_cache_valid_in=(res_from_mem|mem_we)&flag&~exc;
wire [31:0]cache_data_out;
always @(posedge clk) begin
    if(flag&data_cache_valid_in&data_cache_addr_ok)flag<=0;
    else if(~flag&data_cache_data_ok)flag<=1;
end
assign busy=~data_cache_data_ok&(res_from_mem|mem_we);

wire [1:0] size  =  mem_op[0]?2:
                    mem_op[1]?1:
                    mem_op[2]?0:0;
wire [3:0]wstrb   = (mem_addr[1:0]==0&size==0)?4'b0001:
                    (mem_addr[1:0]==1&size==0)?4'b0010:
                    (mem_addr[1:0]==2&size==0)?4'b0100:
                    (mem_addr[1:0]==3&size==0)?4'b1000:
                    (mem_addr[1:0]==0&size==1)?4'b0011:
                    (mem_addr[1:0]==2&size==1)?4'b1100:
                    (mem_addr[1:0]==0&size==2)?4'b1111:
                    (mem_addr[1:0]==1&size==2)?4'b1110:0;
wire [7:0]rdata_b=(wstrb==4'b0001)?cache_data_out[7:0]:
                  (wstrb==4'b0010)?cache_data_out[15:8]:
                  (wstrb==4'b0100)?cache_data_out[23:16]:
                  (wstrb==4'b1000)?cache_data_out[31:24]:0;
wire [15:0]rdata_h=(wstrb==4'b0011)?cache_data_out[15:0]:
                (wstrb==4'b1100)?cache_data_out[31:16]:0;
wire [31:0]rdata_b_exten=mem_op[3]?{{24'b0},rdata_b}:{{24{rdata_b[7]}},rdata_b};
wire [31:0]rdata_h_exten=mem_op[3]?{{16'b0},rdata_h}:{{24{rdata_h[15]}},rdata_h};
wire [31:0]cache_data_after_proc=mem_op[0]?cache_data_out:
                                 mem_op[1]?rdata_h_exten:
                                 mem_op[2]?rdata_b_exten:0;
wire [64:0] processed_wdata=mem_addr[1:0]==0?{{32'b0},mem_w_data}:
                            mem_addr[1:0]==1?{{24'b0},mem_w_data,{8'b0}}:
                            mem_addr[1:0]==2?{{16'b0},mem_w_data,{16'b0}}:
                            mem_addr[1:0]==3?{{8'b0},mem_w_data,{24'b0}}:0;
wire uncache_in=mem_addr[31:16]==16'hbfaf;
cache data_cache0(
    .clk_g(clk),
    .resetn(resetn),
//cpu<->cache
    .valid(data_cache_valid_in),
    .op(mem_we),
    .index(mem_addr[11:4]),
    .tag(mem_addr[31:12]),
    .offset(mem_addr[3:0]),
    .wstrb(wstrb),
    .wdata(processed_wdata[31:0]),
    .addr_ok(data_cache_addr_ok),
    .data_ok(data_cache_data_ok),
    .rdata(cache_data_out),
    .is_uncache(uncache_in),
//cache<->axi
    .rd_req(data_rd_req),
    .rd_type(data_rd_type),
    .rd_addr(data_rd_addr),
    .rd_rdy(data_rd_rdy),
    .ret_valid(data_ret_valid),
    .ret_last(data_ret_last),
    .ret_data(data_ret_data),
    
    .wr_req(data_wr_req),
    .wr_type(data_wr_type),
    .wr_addr(data_wr_addr),
    .wr_wstrb(data_wr_wstrb),
    .wr_data(data_wr_data),
    .wr_rdy(data_wr_rdy)
);

//---------------------------------Dcache---------------------------------

//结果选择
assign res_data=res_from_mem?cache_data_after_proc:mem_addr;

endmodule